/*
  Copyright © 2010  Vinícius dos Santos Oliveira

      This file is part of Touché.

      Touché is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published
      by the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.

      You should have received a copy of the GNU Lesser General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */

#include <QGraphicsSceneMouseEvent>
#include <QGraphicsColorizeEffect>
#include "slideritem.h"

SliderItem::SliderItem(const QString &fileName, const QString &buttonFileName, Qt::Orientation orientation, QGraphicsItem *parentItem) :
        QGraphicsSvgItem(fileName, parentItem),
        orientation(orientation),
        button(new QGraphicsSvgItem(buttonFileName, this)),
        m_minimum(0),
        m_maximum(0xFF),
        m_current(0)
{
    QGraphicsSvgItem::setFlag(QGraphicsItem::ItemIgnoresTransformations);
    button->setFlag(QGraphicsItem::ItemIgnoresTransformations);
}

void SliderItem::setMinimum(unsigned minimum)
{
    if(minimum > m_maximum){
        return;
    }
    m_minimum = minimum;
    emit rangeChanged(minimum, m_maximum);
}

void SliderItem::setMaximum(unsigned maximum)
{
    if(maximum < m_minimum){
        return;
    }
    m_maximum = maximum;
    emit rangeChanged(m_minimum, maximum);
}

void SliderItem::setValue(unsigned value)
{
    if(value < m_minimum || value > m_maximum){
        return;
    }
    if(value != m_current){
        m_current = value;
        if(orientation == Qt::Horizontal){
            qreal rate = static_cast<qreal>(value - m_minimum) / static_cast<qreal>(m_maximum - m_minimum);
            button->setX(rate * (boundingRect().width() - button->boundingRect().width()));
        }else{
            qreal rate = static_cast<qreal>(value - m_minimum) / static_cast<qreal>(m_maximum - m_minimum);
            button->setY((1 -rate) * (boundingRect().height() - button->boundingRect().height()));
        }
        emit valueChanged(value);
    }
}

//TODO: O SliderItem usa event->pos() para receber coordenadas do mouse e fazer cálculos,
//porém é provável que isso não seja apropriado
void SliderItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsSvgItem::mousePressEvent(event);
    event->accept();
    emit sliderPressed();
    QGraphicsColorizeEffect *effect = new QGraphicsColorizeEffect;
    effect->setColor(QColor(0xFF, 0xFF, 0xFF, 0x7F));
    effect->setStrength(0.75);
    button->setGraphicsEffect(effect);
    if(orientation == Qt::Horizontal){
        qreal pos = event->pos().x() - button->boundingRect().width() / 2.;
        qreal limit = boundingRect().width() - button->boundingRect().width();
        if(pos < limit){
            if(pos > 0.){
                button->setX(pos);
            }else{
                button->setX(0.);
            }
        }else{
            button->setX(limit);
        }
        unsigned newValue = button->x() / (boundingRect().width() - button->boundingRect().width()) *
                            (m_maximum - m_minimum) + m_minimum;
        if(m_current != newValue){
            emit valueChanged(m_current = newValue);
        }
    }else{
        qreal pos = event->pos().y() - button->boundingRect().height() / 2.;
        qreal limit = boundingRect().height() - button->boundingRect().height();
        if(pos < limit){
            if(pos > 0.){
                button->setY(pos);
            }else{
                button->setY(0.);
            }
        }else{
            button->setY(limit);
        }
        unsigned newValue = (boundingRect().height() - button->boundingRect().height() - button->y()) /
                            (boundingRect().height() - button->boundingRect().height()) *
                            (m_maximum - m_minimum) + m_minimum;
        if(m_current != newValue){
            emit valueChanged(m_current = newValue);
        }
    }
}

void SliderItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsSvgItem::mouseReleaseEvent(event);
    emit sliderReleased();
    button->setGraphicsEffect(NULL);
}

void SliderItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsSvgItem::mouseMoveEvent(event);
    if(orientation == Qt::Horizontal){
        qreal pos = event->pos().x() - button->boundingRect().width() / 2.;
        qreal limit = boundingRect().width() - button->boundingRect().width();
        if(pos < limit){
            if(pos > 0.){
                button->setX(pos);
            }else{
                button->setX(0.);
            }
        }else{
            button->setX(limit);
        }
        unsigned newValue = button->x() / (boundingRect().width() - button->boundingRect().width()) *
                            (m_maximum - m_minimum) + m_minimum;
        if(m_current != newValue){
            emit valueChanged(m_current = newValue);
        }
    }else{
        qreal pos = event->pos().y() - button->boundingRect().height() / 2.;
        qreal limit = boundingRect().height() - button->boundingRect().height();
        if(pos < limit){
            if(pos > 0.){
                button->setY(pos);
            }else{
                button->setY(0.);
            }
        }else{
            button->setY(limit);
        }
        unsigned newValue = (boundingRect().height() - button->boundingRect().height() - button->y()) /
                            (boundingRect().height() - button->boundingRect().height()) *
                            (m_maximum - m_minimum) + m_minimum;
        if(m_current != newValue){
            emit valueChanged(m_current = newValue);
        }
    }
}

void SliderItem::wheelEvent(QGraphicsSceneWheelEvent *event)
{
    if(event->orientation() != orientation){
        return;
    }
    this->setValue(m_current + event->delta() / 120);
}
